/*
 * ==========================================================================================================
 * 
 *                                               SplitScreen demo
 *                                              
 * ==========================================================================================================
 * 
 * 
 * 
 * - Engine control
 * Espace - quit
 * F1 - view console
 * F2 - toggle fullscreen mode
 * F3 - antialiasing
 * F4 - view node model
 * F5 - view collisions
 * F6 - collision fillmode
 * F7 - view partitioner
 * 
 * - Demo control
 * W - move forward
 * S - move backward
 * A - strafe left
 * D - strafe right
 * Left shift - move down
 * Space - move up
 * Mouse move - look
 */

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace SplitScreen
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {

    #region fields

        // engine and render
        private DARE.CDare m_Dare;
        private DARE.CScene m_Scene;
        private DARE.CRender3D m_Render;

        // cameras
        private DARE.CFirstPersonCamera[] m_camera = new DARE.CFirstPersonCamera[4];
        private Vector3 m_moveCam = Vector3.Zero;

        // key state
        private bool m_rightButtonPressed = false;
        private bool m_leftButtonPressed = false;

        // some nodes
        private DARE.CNode m_cubeNode;
        private DARE.CNode m_cubeChildNode;

    #endregion

    #region ctor

        public Game1()
        {
            // create the engine
            m_Dare = new DARE.CDare(this);
        }

        protected override void Initialize()
        {
 	        base.Initialize();
        }

    #endregion

    #region load / unload content

        protected override void LoadContent()
        {
 	        // general configuration
            m_Dare.Config.General.WindowTitle = "Split screen demo";
            m_Dare.Config.General.ShowMouseCursor = true;
            m_Dare.Config.General.ShowDebugConsole = false;

            // video configuration
            m_Dare.Config.Video.SetResolution(1024, 768);
            m_Dare.Config.Video.FullScreen = false;
            m_Dare.Config.Video.MultiSampling = true;
            m_Dare.Config.Video.UnlockFps = true;

            // start the engine
            m_Dare.RockNRoll();

            // scene creation
            CreateRender();
            CreateCamera();
            CreateScene();
        }

    #endregion

    #region scene creation

        private void CreateRender()
        {
            // simple use, only one scene and one render
            m_Scene = new DARE.CScene("scene");
            m_Render = new DARE.CRender3D("render", new DARE.COctree(200));

            m_Scene.RegisterRenderer(m_Render);
        }

        private void CreateCamera()
        {
            int screenwidth = DARE.CDare.Instance.Config.Video.ResolutionWidth;
            int screenheight = DARE.CDare.Instance.Config.Video.ResolutionHeight;
            int border = 5;
            int width = (screenwidth - border) / 2;
            int height = (screenheight - border) / 2;

            m_camera[0] = new DARE.CFirstPersonCamera("cam0"); // up left
            m_camera[1] = new DARE.CFirstPersonCamera("cam1"); // up right
            m_camera[2] = new DARE.CFirstPersonCamera("cam2"); // down left
            m_camera[3] = new DARE.CFirstPersonCamera("cam3"); // down right

            m_camera[0].ViewPort.RenderArea = new Rectangle(0, height / 4, width, height / 2);
            m_camera[1].ViewPort.RenderArea = new Rectangle(width + border, 0, width, height);
            m_camera[2].ViewPort.RenderArea = new Rectangle(0, height + border, width, height);
            m_camera[3].ViewPort.RenderArea = new Rectangle(width + border + width / 4, height + border, width / 2, height);

            m_Render.CameraMgr.RegisterCamera(m_camera[0]);
            m_Render.CameraMgr.RegisterCamera(m_camera[1]);
            m_Render.CameraMgr.RegisterCamera(m_camera[2]);
            m_Render.CameraMgr.RegisterCamera(m_camera[3]);

            m_camera[0].IsRendering = true;
            m_camera[1].IsRendering = true;
            m_camera[2].IsRendering = true;
            m_camera[3].IsRendering = true;

            m_camera[0].Position = new Vector3(0, 2, 10);
            m_camera[1].Position = new Vector3(10, 2, 0);
            m_camera[2].Position = new Vector3(-2, 2, 5);
            m_camera[3].Position = new Vector3(2, 2, 5);
        }

        private void CreateScene()
        {
            // show option
            m_Render.ShowModelNode = false;
            m_Render.ShowCollision = true;
            m_Render.Partitioner.Show = false;
            m_Render.CollisionFillMode = FillMode.Solid;

            // light
            m_Render.EffectMgr.LighteningEnabled = true;
            m_Render.EffectMgr.AmbientLightColor = Color.White;
            m_Render.EffectMgr.AmbientLightIntensity = 0.1f;

            m_Render.EffectMgr.DirectionalLight0Direction = new Vector3(-0.6f, -1, -0.8f);
            m_Render.EffectMgr.DirectionalLight0DiffuseColor = Color.White;
            m_Render.EffectMgr.DirectionalLight0DiffuseIntensity = 1.5f;

            // sky
            m_Render.SkyMgr.CreateSkybox("sky", "sky/ct");

            // floor
            DARE.CNode floor = m_Render.CreateNode("nFloor");
            floor.Entity.AttachModel(new DARE.CFloorModel());
            floor.Entity.Model.FillMode = FillMode.WireFrame;

            m_cubeNode = m_Render.CreateNode();
            m_cubeNode.Entity.CreateBasicBox();
            m_cubeChildNode = m_cubeNode.CreateChild().TranslateX(1);

            SpawnCubes(new BoundingBox(new Vector3(-100, -4, -4), new Vector3(-2, 4, 4)), 500);
        }

        private void SpawnCubes(BoundingBox container, int number)
        {
            Random rand = DARE.CDare.Instance.Random;
            float precision = 1000.0f;

            for (int i = 0; i < number; ++i)
            {
                float x = rand.Next((int)(container.Min.X * precision), (int)(container.Max.X * precision)) / precision;
                float y = rand.Next((int)(container.Min.Y * precision), (int)(container.Max.Y * precision)) / precision;
                float z = rand.Next((int)(container.Min.Z * precision), (int)(container.Max.Z * precision)) / precision;

                m_Render.CreateNode().SetPosition(x, y, z).Entity.CreateBasicBox();
            }
        }

    #endregion

        #region run

        protected override void Update(GameTime gameTime)
        {
            float time = DARE.CDare.Instance.Config.Time.TimeSinceLastFrame;

            ProcessKeyPressed();

            m_cubeNode.Yaw(time / 400.0f);

            m_camera[0].LookAt(m_cubeChildNode.Position);
            m_camera[1].SetPosition(m_cubeChildNode.Position + Vector3.UnitY + Vector3.UnitX * 3);
            m_camera[1].LookAt(-Vector3.UnitX * 100);
            m_camera[2].LookAt(m_cubeChildNode.Position);
            m_camera[3].LookAt(m_cubeChildNode.Position);

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
        }

    #endregion

    #region input

        private void ProcessKeyPressed()
        {
            foreach (Keys key in m_Dare.InputMgr.Keyboard.KeyPressedEvent)
                switch (key)
                {
                    case Keys.Escape: this.Exit(); break;
                    case Keys.F1: m_Dare.DebugMgr.DebugConsoleEnabled = !m_Dare.DebugMgr.DebugConsoleEnabled; break;
                    case Keys.F2: m_Dare.Config.Video.FullScreen = !m_Dare.Config.Video.FullScreen; break;
                    case Keys.F3: m_Dare.Config.Video.MultiSampling = !m_Dare.Config.Video.MultiSampling; break;
                    case Keys.F4: m_Scene.ActiveRender3D.ShowModelNode = !m_Scene.ActiveRender3D.ShowModelNode; break;
                    case Keys.F5: m_Scene.ActiveRender3D.ShowCollision = !m_Scene.ActiveRender3D.ShowCollision; break;
                    case Keys.F6: m_Scene.ActiveRender3D.CollisionFillMode = m_Scene.ActiveRender3D.CollisionFillMode == FillMode.WireFrame ? FillMode.Solid : FillMode.WireFrame; break;
                    case Keys.F7: m_Scene.ActiveRender3D.Partitioner.Show = !m_Scene.ActiveRender3D.Partitioner.Show; break;

                    //case Keys.W: m_moveCam.Z -= 1; break;
                    //case Keys.S: m_moveCam.Z += 1; break;
                    //case Keys.A: m_moveCam.X -= 1; break;
                    //case Keys.D: m_moveCam.X += 1; break;
                    //case Keys.LeftShift: m_moveCam.Y -= 1; break;
                    //case Keys.Space: m_moveCam.Y += 1; break;

                    default: break;
                }
        }

    #endregion

    }
}
